#pragma once
#include <iostream>
#include <string>
#include <assert.h>
#include <functional>
#include <unordered_map>
#include "Sock.hpp"
#include "Log.hpp"
#include "Err.hpp"
#include "Epoller.hpp"
#include"Util.hpp"
#include"Protocol.hpp"
using namespace std;
using namespace protocol_ns;
class Connection;
class EpollServer;
const static int gport = 8888;
using func_t = std::function<void (Connection*,const Request&)>;
using callback_t =std::function<void(Connection*)>;

// 未来每一个文件描述符（套接字）都要有connection对象
class Connection
{
public:
    Connection(const int& fd,const string& clientip,const uint16_t& clientport) 
    : fd_(fd),
    clientip_(clientip),
    clientport_(clientport)
    {}
    ~Connection()
    {}
    void Register(callback_t recver,callback_t sender,callback_t excepter)
    {
        recver_=recver;
        sender_=sender;
        excepter_=excepter;
    }

public:
    //IO info
    int fd_;
    // 每一个文件描述符自己的缓冲区
    string inbuffer_;
    string outbuffer_;

    //IO处理函数
    callback_t recver_;
    callback_t sender_;
    callback_t excepter_;

    //clientinfo
    string clientip_;
    uint16_t clientport_;

    uint32_t events_;
    EpollServer* R;
};

class EpollServer
{
    const static int gnum = 64;

public:
    EpollServer(func_t func, uint16_t port = gport) : func_(func), port_(port)
    {
    }

    void InitServer()
    {
        // 创建listen套接字 绑定 监听
        listensock_.Socket();
        listensock_.Bind(port_);
        listensock_.Listen();

        // 创建epoll模型
        epoller_.Create();
        logMessage(Debug, "init server success");

        // 2.将listen套接字的connection对象添加到unordered_map
        AddConnection(listensock_.Fd(), EPOLLIN);
    }
    //事件派发
    void Dispatcher()
    {
        int timeout = 1000;
        while (true)
        {
            LoopOnce(timeout);
        }
    }
    void LoopOnce(int timeout)
    {
        int n = epoller_.Wait(revs_, gnum, timeout);

        for (int i = 0; i < n; i++)
        {
            int fd = revs_[i].data.fd;
            uint32_t events = revs_[i].events;

            logMessage(Debug, "当前正在处理%d上的%s", fd, (events & EPOLLIN) ? "EPOLLIN" : "OTHER");
            //将所有的异常情况，最后全部转化成为recv，send的异常！
            if ((events & EPOLLERR) || (events & EPOLLHUP))
                events |= (EPOLLIN | EPOLLOUT);

            if ((events & EPOLLIN) && ConnIsExists(fd))
                connections_[fd]->recver_(connections_[fd]);
            if ((events & EPOLLOUT) && ConnIsExists(fd))
                connections_[fd]->sender_(connections_[fd]);
           //if((events&EPOLLERR)||(events&EPOLLHUP)) connections_[fd]->excepter_(connections_[fd]);

        }
    }
    //
    void AddConnection(int fd, uint32_t events,string ip="127.0.0.1",uint16_t port=gport)
    {
        //设置fd非阻塞
        if(events&EPOLLET) Util::SetNonBlock(fd);
        // 构建connection对象，添加进unorder_map来管理
        Connection *con = new Connection(fd,ip,port);
        //注册回调
        if(fd==listensock_.Fd())
        {
            con->Register(std::bind(&EpollServer::Accepter,this,std::placeholders::_1),nullptr,nullptr);
        }
        else{
            con->Register(std::bind(&EpollServer::Recver, this, std::placeholders::_1),
                           std::bind(&EpollServer::Sender, this, std::placeholders::_1),
                           std::bind(&EpollServer::Excepter, this, std::placeholders::_1));
        }
        con->events_=events;
        con->R=this;
        connections_.insert(std::pair<int, Connection *>(fd, con));
        // fd&&event写到内核中 用户-》内核
        bool r = epoller_.AddModEvent(fd, events,EPOLL_CTL_ADD);
        assert(r);
        (void)r;
        logMessage(Debug,"Addconnection succes,fd:%d,clientinfo:[%s,%d]",con->fd_,ip.c_str(),port);
    }
    bool EnableReadWrite(Connection *con, bool readable, bool writeable)
    {
       con->events_=((readable?EPOLLIN:0)|(writeable?EPOLLOUT:0)|EPOLLET);
        return epoller_.AddModEvent(con->fd_, con->events_,EPOLL_CTL_MOD);
    }
    //连接管理
    void Accepter(Connection* con)
    {
        do
        {
            /* code */
            int err=0;
            (void)con;
        // 1. 新连接到来
        // logMessage(Debug, "get a new link ...");
        std::string clientip;
        uint16_t clientport;
        int sock = listensock_.Accept(&clientip, &clientport,&err);
        if (sock > 0)
        {
             logMessage(Debug, "%s:%d 已经连上了服务器了", clientip.c_str(), clientport);
        // 1.1 此时在这里，我们能不能进行recv/read ? 不能，只有epoll知道sock上面的事件情况，将sock添加到epoll中
        AddConnection(sock, EPOLLIN|EPOLLET,clientip,clientport);
        }
        else{
            if(err==EAGAIN||err==EWOULDBLOCK)
            {
                break;
            }
            else if(err==EINTR) continue;
            else{
                logMessage(Warning,"errstring:%d errcode:%d",strerror(err),err);
                continue;
            }
        }
       
        } while (con->events_&EPOLLET);
        
        
    }
    void Recver(Connection* con)
    {
        do
        {
            /* code */
            char buffer[1024];
            ssize_t n=recv(con->fd_,buffer,sizeof(buffer)-1,0);
            if(n>0)
            {
                buffer[n]=0;
                con->inbuffer_+=buffer;
                string requestStr;
                int n=protocol_ns::ParsePackage(con->inbuffer_,&requestStr);
                if(n>0)
                {
                    requestStr=protocol_ns::RemoveHeader(requestStr,n);
                    Request req;
                    req.Deserialize(requestStr);
                    func_(con,req);
                }
            }
            else if(n==0)
            {
                con->excepter_(con);
            }
            else
            {
                if(errno==EAGAIN||errno==EWOULDBLOCK) break;
                else if(errno==EINTR) continue;
                else 
                {
                    con->excepter_(con);
                    break;
                }
            }
        } while (con->events_&EPOLLET);
        //根据协议进行分析

        
        
    }
    void Sender(Connection* con)
    {
        do 
        {
            ssize_t n=send(con->fd_,con->outbuffer_.c_str(),con->outbuffer_.size(),0);
            if(n>0)
            {
                con->outbuffer_.erase(0,n);
                if(con->outbuffer_.empty())
                {
                    EnableReadWrite(con,true,false);
                    break;
                }
                else{
                    EnableReadWrite(con,true,true);

                }

            }
            else
            {
                if((errno==EAGAIN||errno==EWOULDBLOCK)) break;
                else if(errno==EINTR) continue;
                else{
                    con->excepter_(con);
                    break;
                }
            }

        }while(con->events_&EPOLLET);
    }
     void Excepter(Connection* con)
    {
    }
    bool ConnIsExists(int fd)
    {
        return connections_.find(fd) != connections_.end();
    }

    ~EpollServer()
    {
        listensock_.Close();
        epoller_.Close();
    }

private:
    uint16_t port_;
    Sock listensock_;
    Epoller epoller_; // epoll模型
    // 定义一个捞取就绪事件的列表
    struct epoll_event revs_[gnum];
    func_t func_;
    unordered_map<int, Connection *> connections_;
};